package com.gitee.shigen.lucene.dao;

import cn.hutool.core.util.StrUtil;
import com.gitee.shigen.lucene.util.DocumentUtil;
import com.gitee.shigen.lucene.vo.Content;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.springframework.stereotype.Component;

/**
 * @author shigenfu
 */
@Slf4j
@Component
public class ContentDaoImpl implements ContentDao {

    @Resource
    private IndexWriter indexWriter;

    @Resource
    private IndexSearcher indexSearcher;

    @Resource
    private Analyzer analyzer;


    /**
     * 删除索引
     */
    @Override
    public void deleteAll() throws IOException {
        Long result = indexWriter.deleteAll();
        // 清空回收站
        indexWriter.forceMergeDeletes();
        indexWriter.commit();
        log.info("deleted:{}", result);
    }

    @Override
    public long save(List<Content> contentList) throws IOException {
        List<Document> docs = new ArrayList<>();
        for (Content content : contentList) {
            docs.add(DocumentUtil.Content2Document(content));
        }
        long count = indexWriter.addDocuments(docs);
        indexWriter.commit();
        log.info("save count:{}", count);
        return count;
    }

    @Override
    public void deleteIndexById(String id) throws IOException {
        indexWriter.deleteDocuments(new Term("id", id));
        indexWriter.commit();
    }

    @Override
    public Content getDocumentById(String id) throws IOException {
        Term term = new Term("id", id);
        Query query = new TermQuery(term);

        TopDocs topDocs = indexSearcher.search(query, 1);
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;

        // 如果找到匹配的文档，则返回该文档
        if (scoreDocs.length > 0) {
            int docId = scoreDocs[0].doc;
            Document doc = indexSearcher.doc(docId);
            return DocumentUtil.document2Content(doc);
        }
        return null;
    }

    @SneakyThrows
    public List<Content> search(String[] fields, String keyword, int page, int pageSize) {

        // 创建多字段查询解析器
        MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer);
        Query query = parser.parse("*:*");
        if (StrUtil.isNotEmpty(keyword)) {
            query = parser.parse(keyword);
        }

        // 执行搜索
        TopDocs topDocs = indexSearcher.search(query, page * pageSize);

        // 获取分页结果
        ScoreDoc[] hits = topDocs.scoreDocs;
        int start = (page - 1) * pageSize;
        int end = Math.min(start + pageSize, hits.length);

        // 高亮处理
        SimpleHTMLFormatter formatter = new SimpleHTMLFormatter("<span class=\"highlight\">", "</span>");
        Highlighter highlighter = new Highlighter(formatter, new QueryScorer(query));

        // 构建搜索结果列表
        List<Content> results = new ArrayList<>();
        for (int i = start; i < end; i++) {
            int docId = hits[i].doc;
            Document document = indexSearcher.doc(docId);

            Content content = DocumentUtil.document2Content(document);
            // 高亮标题和描述字段
            String title = highlighter.getBestFragment(analyzer, "title", document.get("title"));
            String description = highlighter.getBestFragment(analyzer, "desc", document.get("desc"));

            // 如果无法高亮，则使用原始值
            if (title == null) {
                title = document.get("title");
            }
            if (description == null) {
                description = document.get("desc");
            }
            content.setTitle(title);
            content.setDesc(description);

            results.add(content);
        }
        return results;
    }
}
